---
apiVersion: deckhouse.io/v1alpha1
kind: FalcoAuditRules
metadata:
  name: fstec
  {{- include "helm_lib_module_labels" (list . (dict "app" $.Chart.Name)) | nindent 2 }}
spec:
  rules:
    - macro:
        name: never_true
        condition: (evt.num=0)
    - macro:
        name: always_true
        condition: (evt.num>=0)
    - macro:
        name: open_write
        condition: (evt.type in (open,openat,openat2) and evt.is_open_write=true and fd.typechar='f' and fd.num>=0)
    - macro:
        name: open_read
        condition: (evt.type in (open,openat,openat2) and evt.is_open_read=true and fd.typechar='f' and fd.num>=0)
    - macro:
        name: open_directory
        condition: (evt.type in (open,openat,openat2) and evt.is_open_read=true and fd.typechar='d' and fd.num>=0)
    - macro:
        name: open_file_failed
        condition: (evt.type in (open,openat,openat2) and fd.typechar='f' and fd.num=-1 and evt.res startswith E)
    - macro:
        name: chmod
        condition: (evt.type in (chmod, fchmod, fchmodat) and evt.dir=<)
    - macro:
        name: rename
        condition: (evt.type in (rename, renameat, renameat2))
    - macro:
        name: mkdir
        condition: (evt.type in (mkdir, mkdirat))
    - macro:
        name: remove
        condition: (evt.type in (rmdir, unlink, unlinkat))
    - macro:
        name: modify
        condition: (rename or remove)
    - macro:
        name: container
        condition: (container.id != host)
    - macro:
        name: spawned_process
        condition: (evt.type in (execve, execveat) and evt.dir=<)
    - macro:
        name: proc_name_exists
        condition: (proc.name!="<NA>")
    - macro:
        name: package_mgmt_ancestor_procs
        condition: proc.pname in (package_mgmt_binaries) or proc.aname[2] in (package_mgmt_binaries) or proc.aname[3] in (package_mgmt_binaries) or proc.aname[4] in (package_mgmt_binaries)
    - macro:
        name: bin_dir_mkdir
        condition: |
          (evt.arg.path startswith /bin/ or evt.arg.path startswith /sbin/ or evt.arg.path startswith /usr/bin/ or evt.arg.path startswith /usr/sbin/)
    - macro:
        name: bin_dir_rename
        condition: |
          (evt.arg.path startswith /bin/ or evt.arg.path startswith /sbin/ or evt.arg.path startswith /usr/bin/ or evt.arg.path startswith /usr/sbin/ or evt.arg.name startswith /bin/ or evt.arg.name startswith /sbin/ or evt.arg.name startswith /usr/bin/ or evt.arg.name startswith /usr/sbin/ or evt.arg.oldpath startswith /bin/ or evt.arg.oldpath startswith /sbin/ or evt.arg.oldpath startswith /usr/bin/ or evt.arg.oldpath startswith /usr/sbin/ or evt.arg.newpath startswith /bin/ or evt.arg.newpath startswith /sbin/ or evt.arg.newpath startswith /usr/bin/ or evt.arg.newpath startswith /usr/sbin/)
    - list:
        name: package_mgmt_binaries
        items:
          - rpm_binaries
          - deb_binaries
          - update-alternat
          - gem
          - npm
          - pip
          - pip3
          - sane-utils.post
          - alternatives
          - chef-client
          - apk
          - snapd
    - macro:
        name: package_mgmt_procs
        condition: proc.name in (package_mgmt_binaries)
    - macro:
        name: kevt
        condition: (jevt.value[/stage] in (k8s_audit_stages))
    - macro:
        name: kevt_started
        condition: (jevt.value[/stage]=ResponseStarted)
    - macro:
        name: consider_activity_events
        condition: (always_true)
    - macro:
        name: kactivity
        condition: (kevt and consider_activity_events)
    - macro:
        name: response_successful
        condition: (ka.response.code startswith 2)
    - macro:
        name: kget
        condition: ka.verb=get
    - macro:
        name: kcreate
        condition: ka.verb=create
    - macro:
        name: kmodify
        condition: (ka.verb in (create,update,patch))
    - macro:
        name: kdelete
        condition: ka.verb=delete
    - macro:
        name: writable_verbs
        condition: kcreate or kmodify or kdelete
    - macro:
        name: namespace
        condition: ka.target.resource=namespaces
    - macro:
        name: serviceaccount
        condition: ka.target.resource=serviceaccounts
    - macro:
        name: clusterrole
        condition: ka.target.resource=clusterroles
    - macro:
        name: clusterrolebinding
        condition: ka.target.resource=clusterrolebindings
    - macro:
        name: role
        condition: ka.target.resource=roles
    - macro:
        name: secret
        condition: ka.target.resource=secrets
    - macro:
        name: pod
        condition: ka.target.resource=pods and not ka.target.subresource exists
    - macro:
        name: pod_subresource
        condition: ka.target.resource=pods and ka.target.subresource exists
    - list:
        name: known_drop_and_execute_containers
        items: []
    - macro:
        name: user_known_container_drift_activities
        condition: (always_true)
    - macro:
        name: user_known_modify_bin_dir_activities
        condition: (always_true)
    - macro:
        name: user_known_package_manager_in_container
        condition: (always_true)
    - macro:
        name: user_known_exec_pod_activities
        condition: (always_true)
    - macro:
        name: user_known_pod_debug_activities
        condition: (always_true)
    - macro:
        name: system_namespace
        condition: ((ka.target.namespace in (kube-system, kube-public, default)) or (ka.target.name startswith "d8-"))
    - rule:
        name: Launch Package Management Process in container
        condition: |
          spawned_process and container and user.name != "_apt" and package_mgmt_procs and not package_mgmt_ancestor_procs and not user_known_package_manager_in_container
        desc: Package management process ran inside container
        output: |
          Package management process launched in container (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline pid=%proc.pid container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag exe_flags=%evt.arg.flags)
        priority: Error
        tags:
          - fstec
          - container_drift
    - rule:
        name: Drop and execute new binary in container
        condition: |
          spawned_process and container and proc.is_exe_upper_layer=true and not container.image.repository in (known_drop_and_execute_containers)
        desc: Detect if an executable not belonging to the base image of a container is being executed. The drop and execute pattern can be observed very often after an attacker gained an initial foothold. is_exe_upper_layer filter field only applies for container runtimes that use overlayfs as union mount filesystem.
        output: |
          Executing binary not part of base image (user=%user.name user_loginuid=%user.loginuid user_uid=%user.uid comm=%proc.cmdline exe=%proc.exe container_id=%container.id image=%container.image.repository proc.name=%proc.name proc.sname=%proc.sname proc.pname=%proc.pname proc.aname[2]=%proc.aname[2] exe_flags=%evt.arg.flags proc.exe_ino=%proc.exe_ino proc.exe_ino.ctime=%proc.exe_ino.ctime proc.exe_ino.mtime=%proc.exe_ino.mtime proc.exe_ino.ctime_duration_proc_start=%proc.exe_ino.ctime_duration_proc_start proc.exepath=%proc.exepath proc.cwd=%proc.cwd proc.tty=%proc.tty container.start_ts=%container.start_ts proc.sid=%proc.sid proc.vpgid=%proc.vpgid evt.res=%evt.res)
        priority: Critical
        tags:
          - fstec
          - container_drift
    - rule:
        name: Container drift detected (chmod)
        condition: |
          chmod and container and not runc_writing_exec_fifo and not runc_writing_var_lib_docker and not user_known_container_drift_activities and evt.rawres>=0 and (
            (evt.arg.mode contains "S_IXUSR")
            or (evt.arg.mode contains "S_IXGRP")
            or (evt.arg.mode contains "S_IXOTH")
          )
        desc: New executable created in a container due to chmod
        output: Drift detected (chmod), new executable created in a container (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline pid=%proc.pid filename=%evt.arg.filename name=%evt.arg.name mode=%evt.arg.mode event=%evt.type)
        priority: Error
        tags:
          - fstec
          - container_drift
    - macro:
        name: runc_writing_exec_fifo
        condition: (proc.cmdline="runc:[1:CHILD] init" and fd.name=/exec.fifo)
    - macro:
        name: runc_writing_var_lib_docker
        condition: (proc.cmdline="runc:[1:CHILD] init" and evt.arg.filename startswith /var/lib/docker)
    - macro:
        name: runc_writing_var_lib_containerd
        condition: (proc.cmdline="runc:[1:CHILD] init" and evt.arg.filename startswith /var/lib/containerd)
    - rule:
        name: Container drift detected (open+create)
        condition: |
          evt.type in (open,openat,openat2,creat) and evt.is_open_exec=true and container and not runc_writing_exec_fifo and not runc_writing_var_lib_docker and not runc_writing_var_lib_containerd and not user_known_container_drift_activities and evt.rawres>=0
        desc: New executable created in a container due to open+create
        output: Drift detected (open+create), new executable created in a container (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline pid=%proc.pid filename=%evt.arg.filename name=%evt.arg.name mode=%evt.arg.mode event=%evt.type)
        priority: Error
        tags:
          - fstec
          - container_drift
    - rule:
        name: Modify binary dirs
        condition: |
          container and bin_dir_rename and modify and not package_mgmt_procs and not user_known_modify_bin_dir_activities
        desc: an attempt to modify any file below a set of binary directories.
        output: |
          File below known binary directory renamed/removed (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline pid=%proc.pid pcmdline=%proc.pcmdline operation=%evt.type file=%fd.name %evt.args container_id=%container.id image=%container.image.repository)
        priority: Error
        tags:
          - fstec
          - container_drift
    - rule:
        name: K8s Pod created
        condition: (kevt and kcreate and pod and response_successful)
        desc: Detect any attempt to create a pod
        output: K8s Pod Created (user=%ka.user.name pod=%ka.target.name ns=%ka.target.namespace resource=%ka.target.resource resp=%ka.response.code decision=%ka.auth.decision reason=%ka.auth.reason)
        priority: Informational
        tags:
          - fstec
          - container_drift
        source: K8sAudit
    - rule:
        name: K8s Pod deleted
        condition: (kevt and kdelete and pod and response_successful)
        desc: Detect any attempt to delete a pod
        output: K8s Pod Deleted (user=%ka.user.name pod=%ka.target.name ns=%ka.target.namespace resource=%ka.target.resource resp=%ka.response.code decision=%ka.auth.decision reason=%ka.auth.reason)
        priority: Informational
        tags:
          - fstec
          - container_drift
        source: K8sAudit
    - rule:
        name: ServiceAccount created in a system namespace
        condition: |
          kevt and serviceaccount and kcreate and system_namespace and response_successful
        desc: Detect any attempt to create a serviceaccount in the kube-system or kube-public namespaces
        output: Service account created in kube namespace (user=%ka.user.name serviceaccount=%ka.target.name resource=%ka.target.resource ns=%ka.target.namespace)
        priority: Warning
        tags:
          - fstec
          - rbac_drift
        source: K8sAudit
    - rule:
        name: Attach to cluster-admin Role
        condition: |
          kevt and clusterrolebinding and kcreate and ka.req.binding.role=cluster-admin
        desc: Detect any attempt to create a ClusterRoleBinding to the cluster-admin user
        output: Cluster Role Binding to cluster-admin role (user=%ka.user.name subject=%ka.req.binding.subjects)
        priority: Warning
        tags:
          - fstec
          - rbac_drift
        source: K8sAudit
    - rule:
        name: ClusterRole with wildcard created
        condition: |
          kevt and (role or clusterrole) and kcreate and (
            ka.req.role.rules.resources intersects ("*")
            or ka.req.role.rules.verbs intersects ("*")
          )
        desc: Detect any attempt to create a Role/ClusterRole with wildcard resources or verbs
        output: Created Role/ClusterRole with wildcard (user=%ka.user.name role=%ka.target.name resource=%ka.target.resource rules=%ka.req.role.rules)
        priority: Warning
        tags:
          - fstec
          - rbac_drift
        source: K8sAudit
    - rule:
        name: Attach/Exec Pod
        condition: |
          kevt_started and pod_subresource and kcreate and ka.target.subresource in (exec,attach) and not user_known_exec_pod_activities
        desc: |
          Detect any attempt to attach/exec to a pod
        output: Attach/Exec to pod (user=%ka.user.name pod=%ka.target.name resource=%ka.target.resource ns=%ka.target.namespace action=%ka.target.subresource command=%ka.uri.param[command])
        priority: Notice
        tags:
          - fstec
          - container_image_access
        source: K8sAudit
    - rule:
        name: EphemeralContainers created
        condition: |
          kevt and pod_subresource and kmodify and ka.target.subresource in (ephemeralcontainers) and not user_known_pod_debug_activities
        desc: |
          Detect any ephemeral container created
        output: Ephemeral container is created in pod (user=%ka.user.name pod=%ka.target.name resource=%ka.target.resource ns=%ka.target.namespace ephemeral_container_name=%jevt.value[/requestObject/ephemeralContainers/0/name] ephemeral_container_image=%jevt.value[/requestObject/ephemeralContainers/0/image])
        priority: Notice
        tags:
          - fstec
          - container_image_access
        source: K8sAudit
    - rule:
        name: ClusterRole with write privileges created
        condition: |
          kevt and (role or clusterrole) and kcreate and writable_verbs
        desc: Detect any attempt to create a Role/ClusterRole that can perform write-related actions
        output: Created Role/ClusterRole with write privileges (user=%ka.user.name role=%ka.target.name resource=%ka.target.resource rules=%ka.req.role.rules)
        priority: Notice
        tags:
          - fstec
          - rbac_drift
        source: K8sAudit
    - rule:
        name: ClusterRole with Pod Exec created
        condition: |
          kevt and (role or clusterrole) and kcreate and ka.req.role.rules.resources intersects ("pods/exec")
        desc: Detect any attempt to create a Role/ClusterRole that can exec to pods
        output: Created Role/ClusterRole with pod exec privileges (user=%ka.user.name role=%ka.target.name resource=%ka.target.resource rules=%ka.req.role.rules)
        priority: Warning
        tags:
          - fstec
          - rbac_drift
        source: K8sAudit
    - rule:
        name: System ClusterRole modified/deleted
        condition: |
          kevt and (role or clusterrole) and (kmodify or kdelete) and (ka.target.name startswith "system:") and not ka.target.name in (system:coredns, system:managed-certificate-controller)
        desc: Detect any attempt to modify/delete a ClusterRole/Role starting with system
        output: System ClusterRole/Role modified or deleted (user=%ka.user.name role=%ka.target.name resource=%ka.target.resource ns=%ka.target.namespace action=%ka.verb)
        priority: Warning
        tags:
          - fstec
          - rbac_drift
        source: K8sAudit
    - rule:
        name: K8s ServiceAccount created
        condition: |
          kactivity and kcreate and serviceaccount and response_successful
        desc: Detect any attempt to create a service account
        output: K8s Serviceaccount Created (user=%ka.user.name serviceaccount=%ka.target.name ns=%ka.target.namespace resource=%ka.target.resource resp=%ka.response.code decision=%ka.auth.decision reason=%ka.auth.reason)
        priority: Notice
        tags:
          - fstec
          - rbac_drift
        source: K8sAudit
    - rule:
        name: K8s ServiceAccount deleted
        condition: |
          kactivity and kdelete and serviceaccount and response_successful
        desc: Detect any attempt to delete a service account
        output: K8s Serviceaccount Deleted (user=%ka.user.name serviceaccount=%ka.target.name ns=%ka.target.namespace resource=%ka.target.resource resp=%ka.response.code decision=%ka.auth.decision reason=%ka.auth.reason)
        priority: Notice
        tags:
          - fstec
          - rbac_drift
        source: K8sAudit
    - rule:
        name: K8s Role/ClusterRole created
        condition: |
          kactivity and kcreate and (clusterrole or role) and response_successful
        desc: Detect any attempt to create a cluster role/role
        output: K8s Cluster Role Created (user=%ka.user.name role=%ka.target.name resource=%ka.target.resource rules=%ka.req.role.rules resp=%ka.response.code decision=%ka.auth.decision reason=%ka.auth.reason)
        priority: Notice
        tags:
          - fstec
          - rbac_drift
        source: K8sAudit
    - rule:
        name: K8s Role/ClusterRole deleted
        condition: kactivity and kdelete and (clusterrole or role) and response_successful
        desc: Detect any attempt to delete a cluster role/role
        output: K8s Cluster Role Deleted (user=%ka.user.name role=%ka.target.name resource=%ka.target.resource resp=%ka.response.code decision=%ka.auth.decision reason=%ka.auth.reason)
        priority: Notice
        tags:
          - fstec
          - rbac_drift
        source: K8sAudit
    - rule:
        name: K8s Role/ClusterRole binding created
        condition: |
          kactivity and kcreate and clusterrolebinding and response_successful
        desc: Detect any attempt to create a clusterrolebinding
        output: K8s Cluster Role Binding Created (user=%ka.user.name binding=%ka.target.name resource=%ka.target.resource subjects=%ka.req.binding.subjects role=%ka.req.binding.role resp=%ka.response.code decision=%ka.auth.decision reason=%ka.auth.reason)
        priority: Notice
        tags:
          - fstec
          - rbac_drift
        source: K8sAudit
    - rule:
        name: K8s Role/ClusterRole binding deleted
        condition: |
          kactivity and kdelete and clusterrolebinding and response_successful
        desc: Detect any attempt to delete a clusterrolebinding
        output: |
          K8s Cluster Role Binding Deleted (user=%ka.user.name binding=%ka.target.name resource=%ka.target.resource resp=%ka.response.code decision=%ka.auth.decision reason=%ka.auth.reason)
        priority: Notice
        tags:
          - fstec
          - rbac_drift
        source: K8sAudit
    - rule:
        name: Read below containerd images dir
        condition: |
          fd.directory in (/var/lib/containerd/io.containerd.grpc.v1.cri/containers/) and evt.dir = < and open_read
        desc: An attempt to read container image file in the containerd directory
        output: |
          File below a known containerd directory opened for reading (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline pid=%proc.pid file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2] container_id=%container.id image=%container.image.repository)
        priority: Notice
        tags:
          - fstec
          - container_image_access
    - rule:
        name: Write below containerd images dir
        condition: |
          fd.directory in (/var/lib/containerd) and evt.dir = < and open_write
        desc: An attempt to change container image file in the containerd directory
        output: |
          File below a known containerd directory opened for writing (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline pid=%proc.pid file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2] container_id=%container.id image=%container.image.repository)
        priority: Error
        tags:
          - fstec
          - container_image_drift
    - rule:
        name: Container tag is not @sha256
        condition: |
          kactivity and kcreate and pod and response_successful and system_namespace and not (ka.req.pod.containers.image contains @sha256:)
        desc: Not all pods are under integrity control in a system namespace
        output: |
          Not all containers are running with the sha256 sum as a tag in a system namespace, which is a potential integrity control mechanism misconfiguration (user=%ka.user.name binding=%ka.target.name resource=%ka.target.resource resp=%ka.response.code decision=%ka.auth.decision reason=%ka.auth.reason image=%ka.req.pod.containers.image)
        priority: Notice
        tags:
          - fstec
          - integrity_control
        source: K8sAudit
    - rule:
        name: Inbound SSH Connection
        condition: |
          (
            (evt.type in (accept,listen) and evt.dir=<)
            or (evt.type in (recvfrom,recvmsg))
          ) and fd.sport=22
        desc: Detect Inbound SSH Connection
        output: Inbound SSH Connection (command=%proc.cmdline pid=%proc.pid connection=%fd.name user=%user.name user_loginuid=%user.loginuid container_id=%container.id image=%container.image.repository type=%evt.type)
        priority: Notice
        tags:
          - fstec
          - auth_attempts
